using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using EMRApi.LogAttribute;
using static LogForParameter.Api.SwaggerHelp.CustomApiVersion;
using System.IdentityModel.Tokens.Jwt;
using LogForParameter.Api.GlobalHelp;
using LogForParameter.Api.ServiceExtensions;
using LogForParameter.Api.AOP;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Swashbuckle.AspNetCore.Filters;
using Autofac;
using Autofac.Extras.DynamicProxy;
using System.Reflection;
using Library.GlobalVars;
using Library.Common;
using LogForParameter.IServices;
using LogForParameter.Model.Models;
using Serilog;
using Library.ServiceExtensions.AutoMapper;
using Library.Common.Helper;
using QuartzTest;
using Library.Helper;
using Quartz;
using LogForParameter.Api.Controllers.JobInstance;
using Microsoft.AspNetCore.HttpOverrides;
using Library.Commom.Redis;
using Library.Middlewares;
using Microsoft.Extensions.AI;
using System.Security.Policy;
namespace LogForParameter.Api
{
    /// <summary>
    /// 开始项目
    /// </summary>
    public class Startup
    {
        public static string _apiName = "万物皆可用";
        /// <summary>
        /// 构造器
        /// </summary>
        /// <param name="configuration"></param>
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        /// <summary>
        /// 配置
        /// </summary>
        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        /// <summary>
        /// 服务配置
        /// </summary>
        /// <param name="services">指定一系列服务描述器的合约(规则)</param>
        public void ConfigureServices(IServiceCollection services)
        {
            var basePath = Path.GetDirectoryName(AppContext.BaseDirectory);

            #region 动态代理原理解析
            //这种代理不能再控制器里面使用.
            // ITest decorator = DispatchProxy.Create<ITest, GenerDecorator>();
            // //将类装换为代理类的TargetClassz属性.
            // ((GenerDecorator)decorator).TargetClass = new Test();
            //var resut=decorator.GetGetOk();
            #endregion
            #region 使用Castle.Core动态代理
            //services.AddScoped<Test>();
            //services.AddScoped<GenerDecorator>();
            //services.AddScoped(provider =>
            //{
            //    //代理生成器
            //    var generator = new ProxyGenerator();
            //    var targetClass = provider.GetService<ITest>();
            //    //代理类
            //    var intercepter = provider.GetService<GenerDecorator>();
            //    var proxy = generator.CreateInterfaceProxyWithTarget(targetClass, intercepter);
            //    return proxy;
            //});
            #endregion
            #region 添加automapper映射
            services.AddAutoMapperSetUp();
            #endregion
            //services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();//全局单例按需添加各种
            //services.AddSingleton(new Appsettings(Configuration));
            services.AddSingleton(new Appsettings(Configuration));
            services.AddCorsSetup();
            #region 添加通信
            //services.AddSignalR();//待完善
            #endregion
            #region 切面缓存
            services.AddSingleton<IRedisCacheManager, RedisCacheManager>();
            services.AddRedisCacheSetup();

            //services.AddMemoryCacheSetup();
            //services.AddRedisInitMqSetup();
            #endregion
            #region orm代码生成sqlsugar
            services.AddSqlsugarSetup();
            services.AddDbSetup();
            #endregion
            #region 短信通知
            services.AddScoped(typeof(SzlhllNewNotice));
            #endregion
            #region quartzServer启动
            services.AddSingleton<ASMJOB>();
            services.AddQuartSetup();
            #endregion
            #region 过滤器
            services.AddControllers(option =>
            {
                option.Filters.Add<OperateTrackAttribute>();//添加过滤器
            });
            #endregion
            #region 注入db上下文
            services.AddDbContext<VillageOfficial>(options => options.UseSqlServer(Configuration.GetConnectionString("Defaultconnection")));
            #endregion
            #region 注入控制器
            //services.AddTransient<IYBOrderTip, YBOrderTip>();
            //services.AddTransient<ILoginPower, LoginPower>();
            #endregion
            #region 获取token信息注入
            services.AddHttpContextSetup();
            #endregion
            #region JWT
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();//清除框架自带的声明类型映射:JwtRegisteredClaimNames 类型自动转换为ClaimTypes
            Permissions.IsUseIds4 = Appsettings.App(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool();
            // 授权+认证 (jwt or ids4)
            services.AddAuthorizationSetup();
            if (Permissions.IsUseIds4)
            {
                services.AddAuthentication_Ids4Setup();
            }
            else
            {
                services.AddAuthentication_JWTSetup();
            }

            #endregion
            #region 设置可以同步读取body中的数据
            services.Configure<KestrelServerOptions>(option =>
            {
                option.AllowSynchronousIO = true;//设置可以同步读取body中的数据
            });
            services.Configure<IISServerOptions>(option =>
            {
                option.AllowSynchronousIO = true;
            });
            #endregion
            #region 注册ollamaChatClient
            services.AddDistributedMemoryCache();
            string ollamaHost = Appsettings.App(["ollama", "host"]);
            //services.AddChatClient(new OllamaChatClient(new Uri("http://localhost:9527/"), /*"deepseek-r1:1.5b"*/))
            services.AddChatClient(new OllamaChatClient(new Uri(ollamaHost), "deepseek-r1:1.5b"))
                 .UseDistributedCache()
                 .UseLogging();
            #endregion
            #region swagger配置
            services.AddSwaggerGen(s =>
            {

                #region 百度来的添加Authorization 此处定义了Scheme的值为小写,而官方提供的默认Scheme是Bearer,当你要使用默认的计划时这里必须要大写,否则认证失败.
                //s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                //{
                //    Description = "JWT Authorization header using the Bearer scheme.",
                //    Name = "Authorization",
                //    In = ParameterLocation.Header,
                //    Scheme = "bearer",
                //    Type = SecuritySchemeType.Http,
                //    BearerFormat = "JWT"
                //});

                //s.AddSecurityRequirement(new OpenApiSecurityRequirement
                //{
                //    {
                //        new OpenApiSecurityScheme
                //        {
                //            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
                //        },
                //        new List<string>()
                //    }
                //});
                #endregion
                #region mvp授权
                // 开启加权小锁
                s.OperationFilter<AddResponseHeadersFilter>();
                s.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();

                // 在header中添加token，传递到后台
                s.OperationFilter<SecurityRequirementsOperationFilter>();


                // ids4和jwt切换
                if (Permissions.IsUseIds4)
                {
                    //接入identityserver4
                    s.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                    {
                        Type = SecuritySchemeType.OAuth2,
                        Flows = new OpenApiOAuthFlows
                        {
                            Implicit = new OpenApiOAuthFlow
                            {
                                AuthorizationUrl = new Uri($"{Appsettings.App(new string[] { "Startup", "IdentityServer4", "AuthorizationUrl" })}/connect/authorize"),
                                Scopes = new Dictionary<string, string> {
                                {
                                    "blog.core.api","ApiResource id"
                                }
                            }
                            }
                        }
                    });
                }
                else
                {
                    // Jwt Bearer 认证，必须是 oauth2
                    s.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                    {
                        Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）\"",
                        Name = "Authorization",//jwt默认的参数名称
                        In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                        Type = SecuritySchemeType.ApiKey
                    });
                }
                #endregion
                //获取版本号
                typeof(MyApiVersion).GetEnumNames().ToList().ForEach(version =>
                {
                    s.SwaggerDoc(version, new OpenApiInfo
                    {
                        Contact = new OpenApiContact
                        {
                            Name = "李逍遥",
                            Email = "1583044952@qq.com",
                            Url = new Uri("http://baidu.com")
                        },
                        Description = "A front-background project build by ASP.NET 6.0 and Vue",
                        Title = $"{_apiName}接口文档2021-8-10",
                        Version = version,
                    });
                });
                s.OperationFilter<ShowSwaggerHeader>();
                //Add comments description
                //
                var basePath = Path.GetDirectoryName(AppContext.BaseDirectory);//get application located directory
                var apiPath = Path.Combine(basePath, "LogForParameter.Api.xml");
                //var dtoPath = Path.Combine(basePath, "ShanDongWebApi.YB.xml");
                s.IncludeXmlComments(apiPath, true);
                //s.IncludeXmlComments(dtoPath, true);
                //添加model层的注释
                var xmlModelPath = Path.Combine(basePath, "LogForParameter.Model.xml");//这个就是Model层的xml文件名
                s.IncludeXmlComments(xmlModelPath);
                //添加ViewModel层的注释
                var xmlViewModelPath = Path.Combine(basePath, "ViewModelMain/ViewModel.xml");//这个就是Model层的xml文件名
                s.IncludeXmlComments(xmlViewModelPath);
            });
            #endregion

            //_service = services;
        }
        /// <summary>
        /// Autofac注入接口层程序集无需引用项目文件
        /// </summary>
        /// <param name="builder"></param>
        public void ConfigureContainer(ContainerBuilder builder)
        {
            #region Autofac注入接口服务
            var basePath = Path.GetDirectoryName(AppContext.BaseDirectory);
            //注册接口类
            //builder.RegisterType<YBOrderTip>().As<IYBOrderTip>();
            //注册要通过反射创建的接口类组件
            var serviceDllFile = Path.Combine(basePath, "LogForParameter.Services.dll");
            var repositoryDllFile = Path.Combine(basePath, "LogForParameter.Repository.dll");
            if (!(File.Exists(serviceDllFile) || File.Exists(repositoryDllFile)))
            {
                var msg = "Repository.dll或service.dll 丢失，因为项目解耦了，所以需要先F6编译，再F5运行，请检查 bin 文件夹，并拷贝。(但是我们项目没有分开两个程序集IServices.dll和Services.dll，没有高度解耦，所以问题不大)现在分了";
                Console.WriteLine(msg);
                Log.Debug(msg);
                return;
            }
            var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
            //var LibraryDllFile = Path.Combine(basePath, "Library.dll");
            //var assemblysLibrary = Assembly.LoadFrom(LibraryDllFile);
            builder.RegisterAssemblyTypes(assemblysRepository/*, assemblysLibrary*/)
                   .AsImplementedInterfaces()
                   .PropertiesAutowired()
                   .InstancePerDependency();
            var assemblysServices = Assembly.LoadFrom(serviceDllFile);
            // AOP 开关，如果想要打开指定的功能，只需要在 appsettigns.json 对应对应 true 就行。
            var cacheType = new List<Type>();
            if (Appsettings.App(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" }).ObjToBool())
            {
                builder.RegisterType<BlogRedisCacheAOP>();
                cacheType.Add(typeof(BlogRedisCacheAOP));
            }
            if (Appsettings.App(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
            {
                builder.RegisterType<BlogCacheAOP>();
                cacheType.Add(typeof(BlogCacheAOP));
            }
            if (Appsettings.App(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
            {
                //builder.RegisterType<BlogTranAOP>();
                //cacheType.Add(typeof(BlogTranAOP));
            }
            if (Appsettings.App(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
            {
                //builder.RegisterType<BlogLogAOP>();
                //cacheType.Add(typeof(BlogLogAOP));
            }
            builder.RegisterAssemblyTypes(assemblysServices)
                .AsImplementedInterfaces()
                .InstancePerDependency()
                .EnableInterfaceInterceptors()
                .InterceptedBy(cacheType.ToArray());//添加拦截器




            //注册只有实现类的服务 这里service 是有接口类的所以注释了先
            //var assemblysInstence = Assembly.Load("ShanDongWebApi.Service");
            //builder.RegisterAssemblyTypes(assemblysInstence);

            //注入实体类名Love
            //只能注入该类中的虚方法
            //builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love)))
            //    .EnableClassInterceptors()
            //    .InterceptedBy(typeof(BlogLogAOP));

            /* builder.Populate(_service);*///将service也注入到aotufac容器中
            #endregion
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        /// <summary>
        /// app环境构建配置
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="applicationLifetime"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime)
        {

            #region 系统自带
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // 在非开发环境中，使用HTTP严格安全传输(or HSTS) 对于保护web安全是非常重要的。
                // 强制实施 HTTPS 在 ASP.NET Core，配合 app.UseHttpsRedirection
                //app.UseHsts();
            }
            #endregion
            app.Use(next => new RequestDelegate(async context =>
            {
                context.Request.EnableBuffering();
                await next(context);
            }));
            #region 重写全局异常捕获中间件
            app.UseExceptionHandle();
            #endregion
            #region 通信部分
            //app.UseSignalRSendMildd();
            #endregion
            #region OllamaChatClient注册
            app.ApplicationServices.GetRequiredService<IChatClient>();
            #endregion
            #region 添加服务运行启动QuartzServer
            if (Appsettings.App(new string[] { "Quartz", "Auto" }).ToBool())
            {
                var quartzserver = app.ApplicationServices.GetRequiredService<IQuartzServer>();
                applicationLifetime.ApplicationStarted.Register(() =>
                {
                    QuartzAutoHelp.QuartzAutoSetUp(quartzserver);
                });
            }
            #endregion;
            #region 配置swagger中间件
            app.UseSwagger();
            app.UseSwaggerUI(s =>
            {
                typeof(MyApiVersion).GetEnumNames()/*.OrderByDescending(s => s)*/.ToList().ForEach(version =>
                {
                    s.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{_apiName} {version}");
                    s.RoutePrefix = "";
                });
            });
            //根据版本名称倒序 遍历展示
            //app.UseSwaggerUI(s =>
            //{
            //    s.SwaggerEndpoint("/swagger/v1/swagger.json", "LogForParameter.Api");
            //    //路径适配，空表示直接访问根目录就可以访问到index.html;可以在launchSettings.json设置访问首页路径;launchUrl:swagger/index.html
            //    s.RoutePrefix = "";
            //});
            #endregion

            app.UseCors(Appsettings.App(new string[] { "Startup", "Cors", "PolicyName" }));
            var proxy = Appsettings.App(new string[] { "Host", "Proxy" }).ObjToBool();
            if (proxy)
            {
                app.UseForwardedHeaders(new ForwardedHeadersOptions
                {
                    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
                });
            }
            app.UseRouting();//顺序注意不能改变
            //app.UseMiddleware<JWTHelp>();//自定义认证
            app.UseAuthentication();//官方认证：推荐使用
            app.UseAuthorization();//授权
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

    }
}
